#include "confparser.h"
using namespace std;

void AppendPath(string *st,string path) {
	char c=st->back();
	if(c!='/'&&c!='\\') st->push_back('/');
	st->append(path);
}
string ExpandUser(string path) {
	if(path[0]=='~'&&(!path[1]||path[1]=='/')) {
		char *e=getenv("HOME");
		if(!e) e=getenv("USERPROFILE");
		if(e) {
			string st(e);
			if(path.size()>2) AppendPath(&st,path.substr(2,-1));
			return st;
		}
	}
	return path;
}
ConfParser::ConfParser(string name,bool search) {
	if(search) {
		string st=ExpandUser("~/.gerald");
		AppendPath(&st,name);
		is.open(st);
	}
	if(!is.is_open()) is.open(name);
}
ConfParser::~ConfParser() {
	if(is.is_open()) is.close();
}
void ConfParser::Parse(void *p) {}

MIMEParser::MIMEParser():ConfParser("mime.conf",true) {}
void MIMEParser::Parse(void *p) {
	MIMEMap *m=(MIMEMap *)p;
	m->clear();
	if(!is.is_open()) return;
	while(!is.eof()) {
		string st,ex;
		stringstream ss;
		int exp;
		getline(is,st);
		if(st.empty()||st[0]=='#') continue;
		ss.str(st);ss.clear();
		ss>>st>>ex;
		if(ss.fail()) continue;
		MIMEType *t=new MIMEType();
		t->type=st;
		ss>>t->expire;
		if(ss.fail()) t->expire=0;
		ss.str(ex);ss.clear();
		while(!ss.eof()) {
			getline(ss,st,',');
			if(!st.empty()) (*m)[st]=t;
		}
	}
}

MainParser::MainParser():ConfParser("httpd.conf",true) {}
bool MainParser::GetArg(stringstream *ss,string *st,bool allowQuote) {
	if(allowQuote) {
		char c;
		for(c=ss->peek();c==' ';ss->ignore(1),c=ss->peek());
		if(c=='"') {
			ss->ignore(1);
			getline(*ss,*st,'"');
			return !ss->eof();
		}
	}
	*ss>>*st;
	return !ss->fail();
}
void MainParser::Parse(void *p) {
	ServerList *m=(ServerList *)p;
	ServerItem *si=NULL;
	HostItem *hi;
	m->clear();
	if(!is.is_open()) return;
	while(!is.eof()) {
		string st,cmd;
		stringstream ss;
		int i;
		getline(is,st);
		if(st.empty()||st[0]=='#') continue;
		ss.str(st);ss.clear();
		if(!GetArg(&ss,&cmd,false)) continue;
		i=cmd.compare("server");
		if(!i||!si) {
			si=new ServerItem();
			m->push_back(si);
			si->threads=40;
			if(i) st.assign("");
			else if(!GetArg(&ss,&st,false)) st.assign("");
			si->addr.FromHost(st,80);
			hi=NULL;
			if(!i) continue;
		}
		if(!cmd.compare("threads"))
			ss>>si->threads;
		else if(!cmd.compare("fcgi")) {
			FCGIItem *f=new FCGIItem();
			if(GetArg(&ss,&st,false)) f->addr.FromHost(st);
			if(GetArg(&ss,&st,false)&&!st.empty()) {
				for(int i=0,j=0;j>=0;i=j+1) {
					j=st.find(',',i);
					if(j<0||j>i)
						si->fcgi[st.substr(i,j<0?-1:j-i)]=f;
				}
			}
		} else {	// HostItem
			i=cmd.compare("host");
			if(!i||!hi) {
				hi=new HostItem();
				if(i) hi->name="";
				else GetArg(&ss,&hi->name,false);
				si->hosts.push_back(hi);
				if(!i) continue;
			}
			if(!cmd.compare("errdocs")) {
				ErrorDocItem e;
				if(!GetArg(&ss,&st,false)) continue;
				e.lb=atoi(st.c_str());
				e.ub=st.find(',');
				if(e.ub<0) e.ub=e.lb;
				else e.ub=atoi(st.c_str()+e.ub+1);
				if(!GetArg(&ss,&e.url,false)) continue;
				hi->errdocs.push_back(e);
			} else if(!cmd.compare("alias")) {
				AliasItem a;
				if(GetArg(&ss,&a.src,false)&&!a.src.empty()
				&&GetArg(&ss,&a.dest,true)&&!a.dest.empty()) {
					a.src=NormalPath(a.src);
					if(a.src.back()=='/') a.src.pop_back();
					a.dest=NormalPath(ExpandUser(a.dest));
					hi->alias.push_back(a);
				}
			} else if(!cmd.compare("rewrite")) {
				RewriteItem r;
				if(GetArg(&ss,&r.src,false)&&!r.src.empty()
				&&GetArg(&ss,&r.dest,true)&&!r.dest.empty()) {
					r.reg.assign(r.src);
					hi->rr.push_back(r);
				}
			}
		}
	}
}
